package org.ithasu.tools.net.mail;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Properties;
import java.util.UUID;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Flags.Flag;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;

import org.ithasu.tools.CollectionTools;
import org.ithasu.tools.Console;
import org.ithasu.tools.ImageTools;

/**
 * Great Tuto:
 * http://java.sun.com/developer/onlineTraining/JavaMail/contents.html
 */
public class GMailTools {

	// -- Read ----------------------------------------

	/**
	 * Note: Call store.close() when done.
	 */
	public static Store connectForRead(Authenticator auth) {
		try {
			// Init session
			Properties props = new Properties();
			props.put("mail.imaps.host", "imap.gmail.com");
			props.put("mail.imaps.port", "993");
			Session session = Session.getInstance(props, auth);

			// Connect
			Store store = session.getStore("imaps");
			store.connect();

			return store;
		} catch (Exception e) {
			return null;
		}
	}

	public static Message[] getInbox(Store store) {
		return getMessages(store, "Inbox");
	}

	public static int getNbUnreadMessages(Message[] messages) {
		if (messages == null) {
			return 0;
		}

		int count = 0;
		for (Message m : messages) {
			try {
				if (!m.isSet(Flag.SEEN)) {
					count++;
				}
			} catch (Exception e) {
				Console.error(e);
			}
		}
		return count;
	}

	/**
	 * Note: call folder.close(...) when done. true if you want to deleted
	 * messages.
	 */
	public static Message[] getMessages(Store store, String folderName) {
		try {
			Folder folder = store.getFolder(folderName);
			folder.open(Folder.READ_ONLY);

			return folder.getMessages();
		} catch (Exception e) {
			Console.error(e);
			return null;
		}
	}

	public static Collection<BufferedImage> getAttachedImages(Message message) {
		ArrayList<BufferedImage> images = new ArrayList<>();

		try {
			Object objContent = message.getContent();
			if (objContent instanceof Multipart) {
				Multipart parts = (Multipart) objContent;
				for (int i = 0; i < parts.getCount(); i++) {
					Part part = parts.getBodyPart(i);
					BufferedImage image = ImageTools.tryOpen(part.getInputStream());
					if (image != null) {
						images.add(image);
					}
				}
			}
		} catch(Exception e) {
			Console.error(e);
		}
		// Multipart mp = (Multipart)message.getContent();
		//
		// for (int i=0, n=multipart.getCount(); i<n; i++) {
		// Part part = multipart.getBodyPart(i));
		//
		// String disposition = part.getDisposition();
		//
		// if ((disposition != null) &&
		// ((disposition.equals(Part.ATTACHMENT) ||
		// (disposition.equals(Part.INLINE))) {
		// saveFile(part.getFileName(), part.getInputStream());
		// }
		// }



		return images;
	}

	// -- Send ----------------------------------------

	public static boolean send(Authenticator auth, String from, String to, String subject, String htmlText,
			Attachment... attachments) {
		try {
			Properties props = new Properties();
			props.put("mail.smtp.auth", "true");
			props.put("mail.smtp.starttls.enable", "true");
			props.put("mail.smtp.host", "smtp.gmail.com");
			props.put("mail.smtp.port", "587");

			Session session = Session.getInstance(props, auth);

			// Init global message
			MimeMultipart multipart = new MimeMultipart("related");

			// Message
			BodyPart messageBodyPart = new MimeBodyPart();
			multipart.addBodyPart(messageBodyPart);

			if (!CollectionTools.isEmpty(attachments)) {
				Object ids[] = new Object[attachments.length];
				int index = 0;
				for (Attachment a : attachments) {
					ids[index++] = a.getID();
					// Create part for the image
					BodyPart attachmentPart = new MimeBodyPart();
					// Add a header to connect to the HTML
					attachmentPart.setHeader("Content-Disposition", "attachment; filename=\"" + a.getFilename() + "\"");
					attachmentPart.setHeader("X-Attachment-Id", a.getID());
					attachmentPart.setHeader("Content-ID", "<" + a.getID() + ">");
					// Fetch the image and associate to part
					attachmentPart.setDataHandler(new DataHandler(a.getDataSource()));
					// Add part to multi-part
					multipart.addBodyPart(attachmentPart);
				}
				htmlText = String.format(htmlText, ids);
			}

			messageBodyPart.setContent(htmlText, "text/html");

			// Associate multi-part with message
			Message message = new MimeMessage(session);
			message.setFrom(new InternetAddress(from));
			message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));
			message.setSubject(subject);
			message.setContent(multipart);

			Transport.send(message);
			return true;
		} catch (MessagingException e) {
			Console.error(e);
			return false;
		}
	}

	// -- Inner Classes ----------------------------------------

	public static abstract class Attachment {
		private final String id;

		public Attachment() {
			id = UUID.randomUUID().toString();
		}

		public String getID() {
			return id;
		}

		public abstract String getFilename();

		public abstract DataSource getDataSource();
	}

	public static class ImageAttachment extends Attachment {
		public final String filename;
		public final ByteArrayDataSource data;

		public ImageAttachment(String name, RenderedImage image) {
			this(name, image, "png");
		}

		public ImageAttachment(String name, RenderedImage image, String extension) {
			this.filename = name + "." + extension;
			byte[] data = ImageTools.toByteArray(image, extension);
			this.data = new ByteArrayDataSource(data, "image/" + extension + ";name=\"" + filename + "\"");
		}

		@Override
		public String getFilename() {
			return filename;
		}

		@Override
		public DataSource getDataSource() {
			return data;
		}
	}

	public static class ColorAttachment extends ImageAttachment {
		public ColorAttachment(String name, Color color) {
			this(name, color, "png");
		}

		public ColorAttachment(String name, Color color, String extension) {
			super(name, ImageTools.generateImage(200, 100, color), extension);
		}
	}

	// Multipart mp = (Multipart)message.getContent();
	//
	// for (int i=0, n=multipart.getCount(); i<n; i++) {
	// Part part = multipart.getBodyPart(i));
	//
	// String disposition = part.getDisposition();
	//
	// if ((disposition != null) &&
	// ((disposition.equals(Part.ATTACHMENT) ||
	// (disposition.equals(Part.INLINE))) {
	// saveFile(part.getFileName(), part.getInputStream());
	// }
	// }

}